#include "gwbase/base/thread_pool.h"
#include "gwbase/base/threadlocal.h"
#include "gwbase/base/string_util.h"
#include <boost/foreach.hpp>
#include <boost/bind.hpp>

namespace dicom {

ThreadPool::ThreadPool(const std::string& name, int max_threads)
    : name_(name),
      max_threads_(max_threads),
      stopping_(false),
      started_(false) {}

ThreadPool::~ThreadPool() {
  if (started_) Stop();
}

void ThreadPool::Start() {
  assert(!started_);
  for (int i = 0; i < max_threads_; ++i) {
    std::string id = StringPrintf("%s:%02d", name_.c_str(), i);
    threads_.push_back(
        ThreadPtr(new Thread(boost::bind(&ThreadPool::Loop, this), id)));
    threads_[i]->Start();
  }
  started_ = true;
}

void ThreadPool::Stop() {
  started_ = false;
  stopping_ = true;
  not_empty_.Broadcast();
  for (int i = 0; i < max_threads_; ++i) threads_[i]->Join();
  threads_.clear();
}

void ThreadPool::RunTask(const Task& t) {
  LockGuard g(mu_);
  while (!tasks_.empty() && !stopping_) {
    not_full_.Wait(&mu_);
  }
  if (stopping_) return;

  assert(tasks_.empty());
  tasks_.push_back(t);
  not_empty_.Signal();
  count_.Increment();
}

ThreadPool::Task ThreadPool::GetNextTask() {
  LockGuard g(mu_);
  Task t;
  while (tasks_.empty() && !stopping_) {
    not_empty_.Wait(&mu_);
  }

  if (stopping_) return t;

  t = tasks_.front();
  tasks_.pop_front();
  not_full_.Signal();
  return t;
}

void ThreadPool::Loop() {
  int count = 0;
  while (true) {
    Task t = GetNextTask();
    if (!t) break;
    t();
    ++count;
    count_.Increment();
  }

  LOG_DEBUG << "Run " << count << " tasks";
}
}
